/*
 * @Author: 0x9DEFA478
 * @Date: 2024-01-13 18:32:46
 * @LastEditTime: 2025-09-14 00:06:36
 * @LastEditors: 0x9DEFA478
 * @Description: 
 * 
 */
#ifndef hConcurrency_H_Concurrency_linux_HPP_
#define hConcurrency_H_Concurrency_linux_HPP_
#include "./H_Concurrency_Empty.hpp"


#if defined(__linux__)||defined(_WIN32)
//mingw-gcc也支持下面的头文件
#include <semaphore.h>
#include <pthread.h>
#include <stdexcept>
#include <string.h>
#include <errno.h>
#endif


namespace H{

  namespace Concurrency{

#if defined(__linux__)||defined(_WIN32)
    class Event_linux{

      public:
        Event_linux(){if(0!=sem_init(&E,0,0)){throw std::runtime_error("Event_linux::Event_linux() fail: errno: "+ std::to_string(errno)+":"+strerror(errno));}}
        ~Event_linux()noexcept{sem_destroy(&E);}

        bool TryAcquire()noexcept{return sem_trywait(&E)==0;}
        void Acquire()noexcept{sem_wait(&E);}

        bool Acquire(usize Timeout)noexcept{
          if(Timeout==0){
            return sem_trywait(&E)==0;
          }
          timespec to;
          clock_gettime(CLOCK_REALTIME,&to);
          H::uint64 ns=to.tv_nsec;
          ns+=1000000LL*Timeout;
          to.tv_sec+=ns/1000000000LL;
          to.tv_nsec=ns%1000000000LL;
          while(sem_timedwait(&E,&to)!=0){
            if(errno!=EINTR){
              return false;
            }
          }
          return true;
        }

        bool Acquire_us(usize Timeout)noexcept{
          if(Timeout==0){
            return sem_trywait(&E)==0;
          }
          timespec to;
          clock_gettime(CLOCK_REALTIME,&to);
          H::uint64 ns=to.tv_nsec;
          ns+=1000LL*Timeout;
          to.tv_sec+=ns/1000000000LL;
          to.tv_nsec+=ns%1000000000LL;
          while(sem_timedwait(&E,&to)!=0){
            if(errno!=EINTR){
              return false;
            }
          }
          return true;
        }

        void Trigger()noexcept{
          sem_post(&E);
        }

      private:
        sem_t E;
    };

    class Lock_linux{

      public:
        Lock_linux(){
          pthread_mutexattr_t a;
          if(0!=pthread_mutexattr_init(&a)){throw std::runtime_error("Lock_linux::Lock_linux() pthread_mutexattr_init fail: errno: "+ std::to_string(errno)+":"+strerror(errno));}
          if(0!=pthread_mutexattr_settype(&a,PTHREAD_MUTEX_RECURSIVE)){throw std::runtime_error("Lock_linux::Lock_linux() pthread_mutexattr_settype fail: errno: "+ std::to_string(errno)+":"+strerror(errno));}
          if(0!=pthread_mutex_init(&L,&a)){throw std::runtime_error("Lock_linux::Lock_linux() pthread_mutex_init fail: errno: "+ std::to_string(errno)+":"+strerror(errno));}
        }
        ~Lock_linux()noexcept{
          pthread_mutex_destroy(&L);
        }

        void Lock()noexcept{
          pthread_mutex_lock(&L);
        }
        
        void Unlock()noexcept{
          pthread_mutex_unlock(&L);
        }

      private:
        pthread_mutex_t L;
    };
#endif

  }
}


#endif //hConcurrency_H_Concurrency_linux_HPP_
